Skip to content

Relocatable ocamlbuild#372

Open
dra27 wants to merge 3 commits intoocaml:masterfrom
dra27:relocatable
Open

Relocatable ocamlbuild#372
dra27 wants to merge 3 commits intoocaml:masterfrom
dra27:relocatable

Conversation

@dra27
Copy link
Copy Markdown
Member

@dra27 dra27 commented Feb 25, 2026

This PR adds support to ocamlbuild to take advantage of OCaml 5.5's relocatable mode. You can see it in action from a 5.5 or 5.6 trunk opam switch by running:

$ make -f configure.make OCAMLBUILD_LIBDIR=..
$ make -j
$ ./ocamlbuild.native -where
/home/dra/ocamlbuild/../lib/ocamlbuild
$ mv ocamlbuild.native bin
$ bin/ocamlbuild.native -where
/home/dra/ocamlbuild/bin/../lib/ocamlbuild

This is "correct" operation at this point - once that binary is in a switch, the directory portion before the .. would be the switch's bin directory.

To be relocatable, ocamlbuild -where will receive the location of the OCaml Standard Library at runtime (that's what Relocatable OCaml does) and then needs to know the relative path to concatenate to it, rather than simply storing the full absolute path.

What actually has to be done when building ocamlbuild to achieve this is very simple: when linking ocamlbuild, the flag -set-runtime-default standard_library_default=$(ocamlopt -config-var standard_library_relative) must be passed to ocamlc/ocamopt. A small bit of extra code is then added to the bottom of ocamlbuild_config.ml which uses the same mechanism as the compiler's Config module to determine the location at runtime of the standard library, and thus where ocamlbuild's standard library is.

What is slightly more complicated is doing that in the general way exposed by configure.make, and invoking that from ocamlbuild.opam. There are obviously multiple ways to do it, but the one I've done here is slightly simpler in the opam file, at a cost of slightly more complexity in configure.make.

The idea is that if OCAMLBUILD_LIBDIR is an explicit-relative path (i.e. it's ., .. or starts ./ or ../) then it describes the relative path from ocamlopt -where to the directory which contains the ocamlbuild library directory. In opam, that's just .. - for an opam switch, ocamlopt -where is the same as $(opam var lib)/ocaml and the ocamlbuild library files are installed in $(opam var lib)/ocamlbuild, which is $(ocamlopt -where)/../ocamlbuild.

The simplification I've then made for opam is to have ocamlbuild.opam always specify OCAMLBUILD_LIBDIR=... It is just converted to an absolute path if the compiler being used is not relocatable. Note that this still makes semantic sense (just): previously, we passed OCAMLBUILD_LIBDIR=%{lib}%, but we know in opam that ocamlopt -where is %{lib}%/ocaml ... in other words, if the compiler is not relocatable, then we'll effectively take OCAMLBUILD_LIBDIR=$(dirname $(ocamlopt -where)) which is... %{lib}%!

Makefile.config contains copies of PREFIX, BINDIR, LIBDIR and MANDIR
from OCaml's Makefile.config. These values were not actually being used,
and they are potentially less reliable with Relocatable OCaml. They've
therefore been removed.

OCAML_LIBDIR was previously a copy of LIBDIR from OCaml's
Makefile.config. However, this file is found by running `ocamlc -where`,
which itself _gives_ the value for OCAML_LIBDIR. For Relocatable OCaml,
`ocamlc -where` is guaranteed to be correct, where the LIBDIR value may
not be, so tweak the generation of Makefile.config to use this value
instead.
In configure.make, specifying a path beginning ./ or ../ or
OCAMLBUILD_LIBDIR enables Relocatable ocamlbuild, as long as the
ocamlbuild binary is being installed in the same directory as the
compiler and the compiler itself is Relocatable OCaml. The relative path
given for OCAMLBUILD_LIBDIR describes how to get from OCaml's Standard
Library to the directory containing the "ocamlbuild" package directory
(in opam, this is just "..").

In this mode, `ocamlbuild -where` is determined relative to the Standard
Library.
PREFIX became prefix quietly in OCaml 4.08
Copy link
Copy Markdown
Member

@gasche gasche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am trying to understand your PR and made various small questions/comments.

Here is the big picture I got from reading the code (your explanation are more confusing than this, but I suppose it's because I haven't absorbed the full subtlety yet):

  • if the user passes an absolute path in OCAML_BUILDIR, it is passed as-is in ocamlbuild_config.ml
  • if the user passes a relative path in OCAML_BUILDIR and the OCaml compiler is relocatable, it is passed as-is
  • if the user passes a relative path in OCAMLBUILD_DIR and the compiler is not relocatable, (OCAML_DIR / OCAML_BUILDIR) (where OCAML_DIR is typically ocamlc -where) is passed

Naive question: ocamlbuild also has modes where it builds plugins, by calling the compiler rather than by dynamic linking. Is that also supported in relocation scenarios?

Comment thread configure.make
$(OCAML_MANDIR))

# OCAMLBUILD_RELOCATABLE is true if:
# 1. The compiler is Relocatable OCaml
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit obscure to me. Maybe "The compiler supports relocation and the 'standard_library_relative' configuration variable"?

Comment thread configure.make

# OCAMLBUILD_RELOCATABLE is true if:
# 1. The compiler is Relocatable OCaml
# 2. ocamlbuild will be installed in the same directory as the compiler
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ocamlbuild binary will be installed in the same directory as the compiler binaries. My first reaction was that of course they should be installed in their own separate directories (I was thinking of libraries).

Comment thread configure.make
OCAML_PREFIX = $(PREFIX)
OCAML_BINDIR = $(BINDIR)
OCAML_LIBDIR = $(LIBDIR)
OCAML_PREFIX = $(prefix)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a change from $PREFIX to $prefix?

let libdir =
if libdir = ".." then
(* Cheeky special case, as it happens to match opam *)
Filename.dirname ocaml_libdir
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand, are there clear benefits to passing dirname ocaml_libdir rather than ocaml_libdir/..?

Comment thread configure.make
src/ocamlbuild_config.ml: OCAML_LIBDIR =
src/ocamlbuild_config.ml: LIBDIR_ABS =

OCB_EXTRA_LINKFLAGS = \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you maybe use the same approach as above to clarify the parallel?

Makefile.config: OCB_EXTRA_LINKFLAGS = \
  ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants